<template>
	<uni-popup ref="popup" type="bottom" @change="popupChange">
		<view class="bg-white flex flex-column" :style="{ height: pickerHeight + 'px' }">
			<PickerTitle @cancel="close" @ok="ok" :title="title" />
			<view v-if="showRoot && !allLoading" class="row-center my-2">
				<view
					v-for="(el, i) in rootData"
					:key="el.value"
					class="relative px-3-1 py-1-3"
					hover-class="opacity-60"
					hover-start-time="0"
					hover-stay-time="50"
					@click="handleRootItem(i)"
				>
					<text class="color-main text-m" :class="[rootSelectIndex === i ? 'font-semibold' : '']">
						{{ el[fieldNames.title] }}
					</text>
					<view v-if="rootSelectIndex === i" class="absolute bottom-0 root-sel-flag"></view>
				</view>
			</view>
			<scroll-view :scroll-x="true" class="nowrap" v-if="!loadFail">
				<view class="px-3-1 border-b b-color-1">
					<view
						v-for="(el, i) in selectedData"
						:key="el[fieldNames.key]"
						class="inline-flex flex-column items-center mr-3-1"
						@click="changeSelected(el, i)"
					>
						<view class="inline-block py-2-2">
							<text class="color-secondary text-title" :class="{ 'color-active': i === activeIndex }">
								{{ el[fieldNames.title] }}
							</text>
						</view>
						<view
							class="inline-block bg-active w-full"
							style="height: 2px"
							:class="{ hidden: i !== activeIndex }"
						></view>
					</view>
				</view>
			</scroll-view>
			<!-- :style="{ height: contentHeight + 'px' }" -->
			<scroll-view class="text-hide flex-1 overflow-hidden" :scroll-y="true">
				<c-skeleton-list
					v-if="pinyinSort"
					:skeletonHeight="150"
					:data="sortLayerData"
					:loading="allLoading"
					:fail="loadFail"
					@retry="retry"
				>
					<view v-for="item in sortLayerData" :key="item.firstChar">
						<text class="block py-2-2 pl-3-1 text-m font-semibold">{{ item.firstChar }}</text>
						<view
							v-for="el in item.data"
							:key="el[fieldNames.key]"
							class="py-2-2 px-3-1 row-center"
							hover-class="bg-color-2"
							hover-start-time="0"
							hover-stay-time="50"
							@click="selectNode(el)"
						>
							<text class="block text-m" :class="[el.selected ? 'color-primary' : 'color-main']">{{
								el[fieldNames.title]
							}}</text>
							<view class="flex-1 ml-1-3" :class="[el.selected ? '' : 'hidden']">
								<text class="iconfont icon-duihao color-primary"></text>
							</view>
							<view :class="[isLeaf(el) ? 'hidden' : '']">
								<text class="color-secondary text-m" v-if="el.loading">加载中...</text>
								<text class="iconfont icon-you color-secondary text-l" v-else></text>
							</view>
						</view>
					</view>
				</c-skeleton-list>
				<c-skeleton-list
					v-else
					:skeletonHeight="150"
					:data="curLayerData"
					:loading="allLoading"
					:fail="loadFail"
					@retry="retry"
				>
					<view
						v-for="el in curLayerData"
						:key="el[fieldNames.key]"
						class="py-2-2 px-3-1 row-center"
						hover-class="bg-color-2"
						hover-start-time="0"
						hover-stay-time="50"
						@click="selectNode(el)"
					>
						<text class="block text-m" :class="[el.selected ? 'color-primary' : 'color-main']">{{
							el[fieldNames.title]
						}}</text>
						<view class="flex-1 ml-1-3" :class="[el.selected ? '' : 'hidden']">
							<text class="iconfont icon-duihao color-primary"></text>
						</view>
						<view :class="[isLeaf(el) ? 'hidden' : '']">
							<text class="color-secondary text-m" v-if="el.loading">加载中...</text>
							<text class="iconfont icon-you color-secondary text-l" v-else></text>
						</view>
					</view>
				</c-skeleton-list>
			</scroll-view>
		</view>
	</uni-popup>
</template>

<script>
import { ref, onMounted, watch, getCurrentInstance, nextTick, computed } from 'vue';
import PickerTitle from '../item-picker/picker-title.vue';
import pinyinPro from '../../../lib/pinyin-pro.js';

export default {
	components: {
		PickerTitle,
	},
	props: {
		//selected loading loaded leaf
		data: {
			default: () => [],
			type: Array,
		},
		getParams: Function,
		getData: Function,
		fieldNames: {
			default: () => ({
				key: 'value',
				title: 'text',
			}),
			type: Object,
		},
		title: String,
		showRoot: Boolean,
		//是否只能选择叶子节点
		selectLeaf: Boolean,
		pinyinSort: Boolean,
	},
	setup(props, ctx) {
		const popup = ref();
		const selectedData = ref([]);
		const curLayerData = ref([]);
		const rootData = ref([]);
		const rootSelectIndex = ref(-1);
		const pickerHeight = ref(uni.upx2px(700));
		const activeIndex = ref(0);
		if (!props.getData) {
			watch(
				() => props.data,
				(data) => {
					if (props.showRoot) {
						rootData.value = data;
						handleRootItem(0);
					} else {
						curLayerData.value = data;
					}
				},
				{
					immediate: true,
				}
			);
		}
		function handleRootItem(i) {
			rootSelectIndex.value = i;
			const item = rootData.value[i];
			curLayerData.value = item.children || [];
			addSelectTip(item.children, true);
		}
		let lastSelectNode = null;
		function addSelectTip(data, isReset) {
			const item = {
				[props.fieldNames.key]: 'tip',
				[props.fieldNames.title]: '请选择',
				node: null,
				data: data || [],
			};
			if (isReset) {
				selectedData.value.forEach((item) => {
					item.data.forEach((el) => {
						el.selected = false;
					});
				});
				selectedData.value = [item];
				activeIndex.value = 0;
			} else {
				selectedData.value.push(item);
			}
		}
		if(!props.showRoot) {
			addSelectTip(props.data);
		}
		async function selectNode(el) {
			if (el.loading) return;
			lastSelectNode = el;
			if (props.getData && !isLeaf(el) && (!el.children || el.children.length === 0) && !el.loaded) {
				el.loading = true;
				const data = await props.getData(el);
				el.loading = false;
				if (data) {
					el.loaded = true;
					el.children = data;
					if (data.length === 0) {
						el.leaf = true;
					}
					doSelectNode();
				}
			} else {
				doSelectNode();
			}
		}
		function doSelectNode() {
			if (!lastSelectNode) return;
			const el = lastSelectNode;
			lastSelectNode = null;
			const { key, title } = props.fieldNames;
			if (el.selected) {
				if (!props.selectLeaf) {
					//可以选择任何节点
					el.selected = false;
					removeAfterActiveIndex();
					selectedData.value.splice(activeIndex.value, 1);
					addSelectTip(el.children);
					return;
				}
			} else {
				//查看当前层有无已选中的
				const node = getCurLayerSelectedNode();
				if (node) {
					node.selected = false;
				}
				el.selected = true;
			}
			if (el.children && el.children.length > 0) {
				const curActiveEl = selectedData.value[activeIndex.value];
				if (curActiveEl.node) {
					if (el[key] === curActiveEl.node[key]) {
						const nextEl = selectedData.value[activeIndex.value + 1];
						if (nextEl) {
							curLayerData.value = nextEl.data;
							activeIndex.value++;
							return;
						}
					} else {
						removeAfterActiveIndex();
					}
				}
				//最后一个选中的数据替换成当前选中的
				selectedData.value[selectedData.value.length - 1] = {
					[key]: el[key],
					[title]: el[title],
					data: curLayerData.value,
					node: el,
				};
				addSelectTip(el.children);
				curLayerData.value = el.children;
				activeIndex.value = selectedData.value.length - 1;
			} else {
				//选中叶子节点，不能再往下选
				selectedData.value[activeIndex.value] = getSelectedItemByNode(el);
				removeAfterActiveIndex();
			}
		}
		function removeAfterActiveIndex() {
			const len = selectedData.value.length;
			if (activeIndex.value < len - 1) {
				for (let i = activeIndex.value + 1; i < len; i++) {
					const node = selectedData.value[i].node;
					if (node) {
						node.selected = false;
					}
				}
				//往后的已选数据全部移除
				selectedData.value.splice(activeIndex.value + 1, len);
			}
		}
		function getSelectedItemByNode(el) {
			return {
				[props.fieldNames.key]: el[props.fieldNames.key],
				[props.fieldNames.title]: el[props.fieldNames.title],
				node: el,
				data: curLayerData.value,
			};
		}
		function getCurLayerSelectedNode() {
			const data = curLayerData.value;
			for (let i = 0; i < data.length; i++) {
				if (data[i].selected) {
					return data[i];
				}
			}
			return null;
		}
		function open(options = {}) {
			if (options.value) {
			}
			popup.value.open();
			if (props.getData && curLayerData.value.length === 0) {
				retry();
			}
		}
		function close() {
			popup.value.close();
		}
		function ok() {
			const keys = [];
			const titles = [];
			const { key, title } = props.fieldNames;
			let hasNoSelect = false;
			selectedData.value.forEach((el) => {
				if (el[key] === 'tip') {
					hasNoSelect = true;
					return;
				}
				keys.push(el[key]);
				titles.push(el[title]);
			});
			if (props.selectLeaf && hasNoSelect) {
				uni.showToast({
					icon: 'none',
					title: '请选择' + props.title,
				});
				return;
			}
			ctx.emit('pick', { keys, titles });
			close();
		}
		function changeSelected(el, i) {
			if (activeIndex.value === i) {
				return;
			}
			activeIndex.value = i;
			curLayerData.value = el.data;
		}
		function isLeaf(el) {
			return el.leaf || (!props.getData && (!el.children || el.children.length === 0));
		}
		const allLoading = ref(false);
		const loadFail = ref(false);
		const { ctx: curCtx } = getCurrentInstance();
		onMounted(() => {
			const info = uni.getSystemInfoSync();
			pickerHeight.value = info.windowHeight * 0.9;
		});
		function popupChange(e) {
			ctx.emit("visibleChange", e);
			// if (e.show) {
			// }
		}
		async function retry() {
			if (allLoading.value) return;
			loadFail.value = false;
			allLoading.value = true;
			const data = await props.getData();
			if (data) {
				if (props.showRoot) {
					rootData.value = data;
					handleRootItem(0);
				} else {
					curLayerData.value = data;
				}
			} else {
				//err
				loadFail.value = true;
			}
			allLoading.value = false;
		}
		
		const { pinyin } = pinyinPro;
		const sortLayerData = computed(() => {
			if(props.pinyinSort) {
				const data = curLayerData.value;
				const obj = {};
				const otherData = [];
				const { key, title } = props.fieldNames;
				data.forEach((el) => {
					if(el[title]) {
						const pinyinArr = pinyin(el[title], { toneType: 'none', type: 'array' });
						const firstPinyin = pinyinArr[0];
						const firstChar = firstPinyin.charAt(0).toUpperCase();
						if(/^[A-Z]$/.test(firstChar)) {
							let arr = obj[firstChar];
							if(!arr) {
								arr = obj[firstChar] = [];
							}
							arr.push(el);
						} else {
							otherData.push(el);
						}
					}
				});
				const newData = [];
				for(let firstChar in obj) {
					newData.push({
						firstChar,
						data: obj[firstChar],
					});
				}
				newData.sort((a, b) => {
					return a.firstChar.localeCompare(b.firstChar);
				});
				if(otherData.length > 0) {
					newData.push({
						firstChar: "#",
						data: otherData
					});
				}
				return newData;
			} else {
				return curLayerData.value;
			}
		});
		return {
			selectedData,
			curLayerData,
			selectNode,
			open,
			close,
			ok,
			activeIndex,
			changeSelected,
			isLeaf,
			allLoading,
			loadFail,
			retry,
			popup,
			rootData,
			rootSelectIndex,
			handleRootItem,
			pickerHeight,
			popupChange,
			sortLayerData,
		};
	},
};
</script>

<style>
.root-sel-flag {
	left: 50%;
	width: 56rpx;
	height: 8rpx;
	margin-left: -28rpx;
	background-image: linear-gradient(270deg, #eeeeee00 0%, #2f60d5 100%);
}
</style>
